require("log")

task = {
	args = function(...)
		local args = ""
		local function rec(argtable)
			for n, arg in pairs(argtable) do
				if type(arg) == "table" then
					rec(arg)
				else
					if arg ~= nil then
						arg = tostring(arg)
						arg = arg:gsub("\"", "\\\"")
						arg = arg:gsub("%$", "\"%$")
						args = args .. string.format(" \"%s\"", arg)
					end
				end
			end
		end
		rec({ ... })
		return args
	end,
	
	execute = function(program, ...)
		local oscommand = program .. " " .. task.args(...)
		log("task", "executing command: %s", oscommand)
		return os.execute(oscommand)
	end,
	
	executebg = function(program, ...)
		local oscommand = string.format("%s %s &", program, task.args(...))
		log("task", "executing command: %s", oscommand)
		os.execute(oscommand)
	end,
	
	executer = function(program, ...)
		local oscommand = program .. " " .. task.args(...)
		log("task", "executing command: %s", oscommand)
		return io.popen(oscommand, "r")
	end,
	
	executerh = function(handler, program, ...)
		local stream = task.executer(program, ...)
		if stream == nil then return end
		for line in stream:lines() do
			handler(line)
		end
		stream:close()
	end,
	
	executew = function(program, ...)
		local oscommand = string.format("%s %s >/dev/null 2>/dev/null", program, task.args(...))
		log("task", "executing command: %s", oscommand)
		local t = {
			send = function(self, ...)
				self.stdin:write(...)
				self.stdin:flush()
			end,
			
			sendln = function(self, ...)
				self:send(...)
				self:send("\n")
			end,
			
			close = function(self)
				self.stdin:close()
			end
		}
		t.stdin = io.popen(oscommand, "w")
		return t
	end,
	
	executep = function(program, ...)
		assert(type(program) == "string", "program must be a string")
		local pipe = common.getConfig("path.user.pipe")
		local self = {}
		self.program = program
		self.command = program .. task.args(...)
		local oscommand = string.format("%s < %s", self.command, pipe)
		log("task", "executing command: %s", oscommand)
		self.stdout = io.popen(oscommand, "r")
		self.stdin = io.open(pipe, "w")
		self.send = function(self, ...)
			log("task", "sending process `%s' a command: %s", self.program, string.trim(table.concat({ ... }, ", ")))
			self.stdin:write(...)
			self.stdin:flush()
		end
		self.sendln = function(self, ...)
			self:send(..., "\n")
		end
		self.loop = function(self, handler, ...)
			assert((type(handler) == "function") or (handler == nil), "handler must be a function or nil")
			for line in self.stdout:lines() do
				-- log("task", "received a response from process `%s': %s", self.program, line)
				if handler ~= nil then handler(self, line, ...) end
			end
		end
		return self
	end
}


